package rest_cli

import (
	"fmt"
	"gluenet/modules/manager/server/adapter/rest-cli/mysql"
	"gluenet/modules/manager/server/domain/dependency"
	"gluenet/modules/manager/server/domain/entity"
	"gluenet/modules/manager/server/infra/prepare"
	"time"
)

func init() {
	prepare.RegisterRepo(func() {
		cli := NewScheduleCLI()
		prepare.InjectDependency(func() dependency.ScheduleCLI {
			return cli
		})
	})
}

type Schedule struct {
}

func (s *Schedule) Schedule(obj *entity.Instance, order *entity.ScheduleOrder) (*entity.ScheduleOrder, error) {
	var ags []entity.Agent
	if err := mysql.DB.Where(map[string]interface{}{
		"platform": obj.Platform,
		"role":     "normal",
	}).Find(&ags); err != nil {
		return nil, err
	}

	scheduleRes, err := scheduleOne(ags, obj)
	if err != nil {
		return nil, err
	}

	order.OrderState = entity.OrderStateFinished
	order.AgentGuids = scheduleRes
	order.Updated = time.Now()

	return order, nil
}

func (s *Schedule) UnSchedule(obj *entity.ScheduleOrder) (*entity.ScheduleOrder, error) {
	return nil, nil
}

type detail struct {
	Platform string      `json:"platform" yaml:"platform"`
	Res      interface{} `json:"agent_guids" yaml:"res"`
}

func scheduleOne(ags []entity.Agent, obj *entity.Instance) (interface{}, error) {
	switch obj.Platform {
	case entity.PlatformKubernetes:
		if len(ags) == 0 {
			return nil, fmt.Errorf("agent is nil")
		}
		return ags[0].GUID, nil
	case entity.PlatformGluenets:
		if len(ags) == 0 {
			return nil, fmt.Errorf("agent is nil")
		}

		detailInfo, ok := obj.DetailRepoValue.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("detail value is not map[string]interface{}{}")
		}
		spec, ok := detailInfo["spec"]
		if !ok {
			return nil, fmt.Errorf("detail value not contain spec")
		}
		specInfo, ok := spec.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("detail value spec is not map[string]interface{}{}")
		}
		nodeSelector, ok := specInfo["nodeSelector"]
		if !ok {
			return nil, fmt.Errorf("detail value spec not container nodeSelector")
		}
		nodeSelectedList, ok := nodeSelector.(map[string]interface{})
		if !ok {
			return nil, fmt.Errorf("nodeSelector is not map[string]interface")
		}

		var scheduleRes = make(map[string]string, len(nodeSelectedList))
		for k, v := range nodeSelectedList {
			match, guid := false, ""
			for _, agent := range ags {
				if agent.HostName == v.(string) {
					match = true
					guid = agent.GUID
				}
			}
			if !match {
				return nil, fmt.Errorf("instance %v'container %v can't find agent", obj.Name, k)
			}
			scheduleRes[k] = guid
		}

		return scheduleRes, nil
	}
	return nil, fmt.Errorf("do not schedule")
}

func NewScheduleCLI() *Schedule {
	r := &Schedule{}
	return r
}
